package com.yhn.service.impl;

import com.hospital.common.dto.section.SectionStatsDto;
import com.yhn.mapper.SectionStatsMapper;
import com.yhn.service.SectionStatsService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.CannotAcquireLockException;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.DeadlockLoserDataAccessException;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

@Slf4j
@Service
public class SectionStatsServiceImpl implements SectionStatsService {
    @Autowired
    private SectionStatsMapper sectionStatsMapper;

    /**
     * 计算单个板块统计信息
     */
    @Override
    public SectionStatsDto calculateSectionStats(Long sectionId) {
        log.info("开始计算板块 {} 的统计信息", sectionId);

        // 1) 获取基础数据（非事务）
        SectionStatsDto statsData = sectionStatsMapper.getSectionStatsData(sectionId);
        if (statsData == null) {
            log.warn("板块 {} 不存在或已删除", sectionId);
            return null;
        }

        // 2) 计算质量率/参与度（纯内存计算）
        Double qualityRatio = calculateQualityRatio(statsData);
        Long participation = calculateParticipation(statsData);
        System.out.println("qualityRatio = " + qualityRatio);
        System.out.println("participation = " + participation);

        // 3) 短事务写回 + 小次数退避重试，避免锁超时
        int attempt = 0;
        int maxRetry = 3;
        while (true) {
            try {
                writeBack(sectionId, qualityRatio, participation);
                break;
            } catch (CannotAcquireLockException | DeadlockLoserDataAccessException e) {
                attempt++;
                if (attempt >= maxRetry) {
                    throw e;
                }
                try {
                    Thread.sleep(100L << (attempt - 1)); // 100ms,200ms,400ms
                } catch (InterruptedException ignored) {}
            } catch (DataAccessException e) {
                // 其它数据访问异常按同样策略小退避一次，便于应对锁等待
                attempt++;
                if (attempt >= maxRetry) {
                    throw e;
                }
                try {
                    Thread.sleep(100L << (attempt - 1));
                } catch (InterruptedException ignored) {}
            }
        }

        // 设置计算结果
        statsData.setQualityRatio(qualityRatio);
        statsData.setParticipation(participation);

        log.info("板块 {} 统计计算完成 - 质量率: {}, 参与度: {}", sectionId, qualityRatio, participation);
        return statsData;
    }

    /**
     * 仅负责写回数据库的短事务，减少锁持有时间
     */
    @Transactional(isolation = Isolation.READ_COMMITTED, timeout = 5)
    public void writeBack(Long sectionId, Double qualityRatio, Long participation) {
        int rows = sectionStatsMapper.updateSectionStats(sectionId, qualityRatio, participation);
        log.info("统计写回完成 sectionId={}, qualityRatio={}, participation={}, affectedRows={}",
                sectionId, qualityRatio, participation, rows);
    }

    /**
     * 批量计算所有板块的统计信息
     */
    @Override
    public void calculateAllSectionsStats() {
        log.info("开始批量计算所有板块的统计信息");

        // 获取所有活跃板块ID
        List<Long> sectionIds = sectionStatsMapper.findAllActiveSectionIds();
        if (sectionIds.isEmpty()) {
            log.info("没有找到活跃的板块");
            return;
        }

        int successCount = 0;
        int failCount = 0;

        for (Long sectionId : sectionIds) {
            try {
                calculateSectionStats(sectionId);
                successCount++;
            } catch (Exception e) {
                log.error("计算板块 {} 统计信息失败", sectionId, e);
                failCount++;
            }
        }

        log.info("批量计算完成 - 成功: {}, 失败: {}", successCount, failCount);
    }

    /**
     * 获取单个板块统计信息
     */
    @Override
    public SectionStatsDto getSectionStats(Long sectionId) {
        return sectionStatsMapper.getSectionStatsData(sectionId);
    }

    /**
     * 获取所有板块统计信息
     */
    @Override
    public List<SectionStatsDto> getAllSectionsStats() {
        List<Long> sectionIds = sectionStatsMapper.findAllActiveSectionIds();
        List<SectionStatsDto> statsList = new ArrayList<>();

        for (Long sectionId : sectionIds) {
            SectionStatsDto stats = sectionStatsMapper.getSectionStatsData(sectionId);
            if (stats != null) {
                statsList.add(stats);
            }
        }

        return statsList;
    }

    /**
     * 计算板块内容质量率
     * 质量率 = (板块帖子精华率 × 0.7) + (点赞率 × 0.3)
     * 板块帖子精华率 = 板块精华帖数 / 板块总帖数
     * 点赞率 = 板块帖子总点赞数 / 板块帖子总回复数
     */
    private Double calculateQualityRatio(SectionStatsDto stats) {
        if (stats.getTotalPosts() == 0) {
            return 0.0;
        }

        // 计算精华率
        double pinnedRatio = stats.getPinnedPosts().doubleValue() / stats.getTotalPosts().doubleValue();
        System.out.println("pinnedRatio = " + pinnedRatio);

        // 计算点赞率
        double likeRatio = 0.0;
        if (stats.getTotalReplies() > 0) {
            likeRatio = stats.getTotalLikes().doubleValue() / stats.getTotalReplies().doubleValue();
        }

        // 计算质量率
        double qualityRatio = (pinnedRatio * 0.7) + (likeRatio * 0.3);

        // 保留2位小数
        return BigDecimal.valueOf(qualityRatio)
                .setScale(2, RoundingMode.HALF_UP)
                .doubleValue();
    }

    /**
     * 计算板块参与度
     * 板块参与度 = (总回复数 × 2) + (总点赞数 × 1) + (总收藏数 × 3)
     */
    private Long calculateParticipation(SectionStatsDto stats) {
        return (stats.getTotalReplies() * 2) +
                (stats.getTotalLikes() * 1) +
                (stats.getTotalFavorites() * 3);
    }
}
